home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 23
/
AACD 23.iso
/
AACD
/
Online
/
opennap
/
public.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-08
|
7KB
|
260 lines
/* Copyright (C) 2000-1 drscholl@users.sourceforge.net
This is free software distributed under the terms of the
GNU Public License. See the file COPYING for details.
$Id: public.c,v 1.41 2001/02/15 08:39:45 drscholl Exp $ */
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include "opennap.h"
#include "debug.h"
/* static buffer for use by public/emote. these get called a lot so speed
things up by keeping it around. there is no chance of either of these
being called from eachother or used elsewhere so this is safe */
static char PublicBuf[2048];
/* determine if `sender' has permission to send to channel `chan' */
static int
check_permission (CHANNEL * chan, USER * sender)
{
LIST *list;
CHANUSER *chanUser;
for (list = chan->users; list; list = list->next)
{
chanUser = list->data;
if (chanUser->user == sender)
break;
}
if (!list)
{
log ("check_permission: fatal error, could not find %s on channel %s",
sender->nick, chan->name);
return -1;
}
if (sender->level < LEVEL_MODERATOR
&& (chanUser->flags & ON_CHANNEL_OPERATOR) == 0)
{
if (chan->flags & ON_CHANNEL_MODERATED)
{
if ((chanUser->flags & ON_CHANNEL_VOICE) == 0)
{
if (ISUSER (sender->con))
send_cmd (sender->con, MSG_SERVER_NOSUCH,
"permission denied: channel is moderated");
return -1;
}
}
else if (chanUser->flags & ON_CHANNEL_MUZZLED)
{
if (ISUSER (sender->con))
send_cmd (sender->con, MSG_SERVER_NOSUCH,
"permission denied: muzzled on channel");
return -1;
}
}
return 0;
}
/* 402 [ :<sender> ] <channel> <text> */
/* public message to a channel */
HANDLER (public)
{
CHANNEL *chan;
USER *sender;
LIST *list;
char *ptr;
char *sender_name;
CHANUSER *chanUser;
ASSERT (validate_connection (con));
/* save the starting position of the pkt */
ptr = pkt;
if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
return;
if (sender->muzzled)
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH, "You are muzzled.");
return;
}
/* protect against DoS attack against the windows napster client */
if (len - (pkt - ptr) > 180)
{
pkt[180] = 0; /* crop the message */
log ("public: cropped %d byte message from user %s", len,
sender->nick);
}
/* can't use split line here because the text field is considered all
one item */
/* extract the channel name. NOTE: we don't use next_arg() here because
it will strip leading space from the text being sent */
ptr = next_arg_noskip (&pkt);
if (!pkt)
{
unparsable (con);
return;
}
/* find the channel this message is going to. look the user's joined
channels since this should be faster than lookup in the hash table */
if (!(chan = find_channel (sender->channels, ptr)))
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"You are not a member of that channel");
return;
}
if (ISSERVER (con) && chan->local)
{
log ("public: server %s accessed local channel %s", con->host,
chan->name);
return;
}
if (check_permission (chan, sender))
return;
/* relay this message to peer servers */
if (!chan->local)
pass_message_args (con, tag, ":%s %s %s", sender->nick, chan->name,
pkt);
/* the majority of the users in the channel will see this message, so
form it one time */
len = form_message (PublicBuf, sizeof (PublicBuf), MSG_SERVER_PUBLIC,
"%s %s %s", chan->name,
sender->cloaked ? "Operator" : sender->nick, pkt);
/* send this message to everyone in the channel */
for (list = chan->users; list; list = list->next)
{
chanUser = list->data;
ASSERT (chanUser->magic == MAGIC_CHANUSER);
if (ISUSER (chanUser->user->con))
{
if (sender->cloaked && chanUser->user->level > LEVEL_USER)
send_cmd (chanUser->user->con, MSG_SERVER_PUBLIC, "%s %s %s",
chan->name, sender->nick, pkt);
else
queue_data (chanUser->user->con, PublicBuf, len);
}
}
}
/* 824 [ :<user> ] <channel> "<text>" */
HANDLER (emote)
{
CHANUSER *chanUser;
USER *user;
CHANNEL *chan;
char *ptr, *av[2];
char *sender_name;
LIST *list;
ASSERT (validate_connection (con));
ptr = pkt; /* save initial location */
if (pop_user_server (con, tag, &pkt, &sender_name, &user) != 0)
return;
if (user->muzzled)
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH, "You are muzzled");
return;
}
/* protect against DoS attack against the windows napster client */
if (len - (pkt - ptr) > 180)
{
/* crop message */
pkt[179] = '"';
pkt[180] = 0;
log ("emote: cropped %d byte message from user %s", len, user->nick);
}
if (split_line (av, sizeof (av) / sizeof (char *), pkt) < 2)
{
unparsable (con);
return;
}
/* find the channel this message is going to. look the user's joined
channels since this should be faster than lookup in the hash table */
if (!(chan = find_channel (user->channels, av[0])))
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"You are not a member of that channel");
return;
}
if (ISSERVER (con) && chan->local)
{
log ("emote: server %s accessed local channel %s",
con->host, chan->name);
return;
}
if (check_permission (chan, user))
return;
/* relay to peer servers */
if (!chan->local)
pass_message_args (con, tag, ":%s %s \"%s\"", user->nick, chan->name,
av[1]);
/* majority of the users see the same message, so form it once */
len = form_message (PublicBuf, sizeof (PublicBuf), tag, "%s %s \"%s\"",
chan->name,
user->cloaked ? "Operator" : user->nick, av[1]);
/* send this message to all channel members */
for (list = chan->users; list; list = list->next)
{
chanUser = list->data;
ASSERT (chanUser->magic == MAGIC_CHANUSER);
if (ISUSER (chanUser->user->con))
{
if (user->cloaked && chanUser->user->level > LEVEL_USER)
send_cmd (chanUser->user->con, tag, "%s %s \"%s\"",
chan->name, user->nick, av[1]);
else
queue_data (chanUser->user->con, PublicBuf, len);
}
}
}
/* queues a raw message (tag & length header is assumed to be present */
int
send_to_channel (char *name, char *buf, int buflen)
{
CHANNEL *chan;
LIST *list;
CHANUSER *user;
/* if the Channels hash table has not been initialized yet, abort */
if (!Channels)
return -1;
chan = hash_lookup (Channels, name);
/* if nobody is in the log channel, abort */
if (!chan)
return -1;
for (list = chan->users; list; list = list->next)
{
user = list->data;
if (ISUSER (user->user->con))
queue_data (user->user->con, buf, buflen);
}
return 0;
}